package com.mee.log.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mee.common.utils.PageUtil;
import com.mee.log.config.ElasticSearchConfig;
import com.mee.log.service.LogService;
import com.mee.model.common.Page;
import com.mee.model.log.Log;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

//@Service
public class EsLogServiceImpl implements LogService, ApplicationContextAware {

	private static final Logger logger = LoggerFactory.getLogger(EsLogServiceImpl.class);

	private static final String INDEX = "cloud_logs";

	@Autowired
	private RestHighLevelClient client;

	/**
	 * 将日志保存到elasticsearch<br>
	 * 注解@Async是开启异步执行
	 *
	 * @param log
	 */
	@Async
	@Override
	public void save(Log log) {
		if (log.getCreateTime() == null) {
			log.setCreateTime(new Date());
		}
		if (log.getFlag() == null) {
			log.setFlag(Boolean.TRUE);
		}
		logger.info("{}", log);

		String string = JSONObject.toJSONString(log);

		//索引请求对象
		IndexRequest indexRequest = new IndexRequest(INDEX);

		//指定索引文档内容
		indexRequest.source(string, XContentType.JSON);

		//索引响应对象
		try {
			IndexResponse index = client.index(indexRequest, ElasticSearchConfig.COMMON_OPTIONS);
		} catch (IOException e) {
			e.printStackTrace();
		}



		/*//获取响应结果
		DocWriteResponse.Result result = index.getResult();
		System.out.println( result );*/
	}

	@Override
	public Page<Log> findLogs(Map<String, Object> params) {

		//定义返回值
		SearchResponse searchResponse = null;
		//创建查询请求
		SearchRequest searchRequest = new SearchRequest(INDEX);
		//建查询条件
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().trackTotalHits(true);


		//SearchRequestBuilder builder = client.prepareSearch().setIndices(INDEX).setTypes(TYPE);
		if (!CollectionUtils.isEmpty(params)) {
			BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

			// 用户名模糊匹配
			String username = MapUtils.getString(params, "username");
			if (StringUtils.isNoneBlank(username)) {
				queryBuilder.must(QueryBuilders.wildcardQuery("username", "*" + username + "*"));
			}

			// 模块精确匹配
			String module = MapUtils.getString(params, "module");
			if (StringUtils.isNoneBlank(module)) {
				queryBuilder.must(QueryBuilders.matchQuery("module", module));
			}

			String flag = MapUtils.getString(params, "flag");
			if (StringUtils.isNoneBlank(flag)) {
				Boolean bool = Boolean.FALSE;
				if ("1".equals(flag) || "true".equalsIgnoreCase(flag)) {
					bool = Boolean.TRUE;
				}
				queryBuilder.must(QueryBuilders.matchQuery("flag", bool));
			}

			// 大于等于开始日期,格式yyyy-MM-dd
			String beginTime = MapUtils.getString(params, "beginTime");
			if (StringUtils.isNoneBlank(beginTime)) {
				// 转化为0点0分0秒
				Long timestamp = toTimestamp(beginTime + "T00:00:00");
				queryBuilder.must(QueryBuilders.rangeQuery("createTime").from(timestamp));
			}

			// 小于等于结束日期,格式yyyy-MM-dd
			String endTime = MapUtils.getString(params, "endTime");
			if (StringUtils.isNoneBlank(endTime)) {
				// 转化为23点59分59秒
				Long timestamp = toTimestamp(endTime + "T23:59:59");
				queryBuilder.must(QueryBuilders.rangeQuery("createTime").to(timestamp));
			}

			if (queryBuilder != null) {
				searchSourceBuilder.query(queryBuilder);
			}
		}

		searchSourceBuilder.sort("createTime", SortOrder.DESC);

		PageUtil.pageParamConvert(params, true);
		Integer start = MapUtils.getInteger(params, PageUtil.START);
		if (start != null) {
			searchSourceBuilder.from(start);
		}

		Integer length = MapUtils.getInteger(params, PageUtil.LENGTH);
		if (length != null) {
			searchSourceBuilder.size(length);
		}

		//将查询条件放到请求中
		searchRequest.source(searchSourceBuilder);
		//远程查询
		try {
			searchResponse = client.search(searchRequest, ElasticSearchConfig.COMMON_OPTIONS);
		} catch (IOException e) {
			e.printStackTrace();
		}
		SearchHits searchHits = searchResponse.getHits();
		// 总数量
		Long total = searchHits.getTotalHits().value;

		int size = searchHits.getHits().length;
		List<Log> list = new ArrayList<>(size);
		if (size > 0) {
			searchHits.forEach(hit -> {
				String val = hit.getSourceAsString();
				list.add(JSONObject.parseObject(val, Log.class));
			});
		}

		return new Page<>(total.intValue(), list);
	}

	private Long toTimestamp(String str) {
		LocalDateTime localDateTime = LocalDateTime.parse(str);
		Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

		return date.getTime();
	}

	private static ApplicationContext applicationContext = null;

	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		applicationContext = context;
	}

	/**
	 * 初始化日志es索引
	 */
	@PostConstruct
	public void initIndex() {
		LogService logService = applicationContext.getBean(LogService.class);
		// 日志实现是否采用elasticsearch
		boolean flag = (logService instanceof EsLogServiceImpl);
		if (!flag) {
			return;
		}


		try {
			// 判断索引是否存在
			GetIndexRequest request = new GetIndexRequest(INDEX);
			boolean indicesExistsResponse = client.indices().exists(request, ElasticSearchConfig.COMMON_OPTIONS);
			if (indicesExistsResponse) {
				return;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		CreateIndexRequest request = new CreateIndexRequest(INDEX);

		CreateIndexResponse createIndexResponse = null;
		try {
			createIndexResponse = client.indices().create(request, ElasticSearchConfig.COMMON_OPTIONS);
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (createIndexResponse.isAcknowledged()) {
			logger.info("索引：{},创建成功", INDEX);
		} else {
			logger.error("索引：{},创建失败", INDEX);
		}


	}

}
